package compilers.stmt;

import java.io.BufferedWriter;
import java.io.IOException;

import org.antlr.runtime.Token;

import compilers.condition.Term;
import compilers.node.Stmt;
import compilers.output.WarningOutput;
import compilers.table.MemScope;
import compilers.types.IntType;
import compilers.types.Type;

public class While extends Stmt {
	Condition fExpr;
	private Stmt fStatement;
	
	public While(Condition fExpr, Stmt fStatement, Token token) {
		super();
		this.fExpr = fExpr;
		this.setfStatement(fStatement);
		
		if (fExpr instanceof Term) {
			Term t = (Term)fExpr;
			Type tmp = t.compute();
			if (tmp != null) {
				if (tmp.getfValue() > 0) {
					new WarningOutput(token, "Condition in while-loop is always true.");
				}
			} else if(t instanceof Type) {
				Type type = (Type)t;
				if(type.getfValue() != 0) {
					new WarningOutput(token, "Condition in while-loop is always true.");
				}
			}
		}
	}

	public void print(int tab) {
		for (int i=1;i<=tab;i++){System.out.print("\t");}System.out.print("|-");
		System.out.println("While");
		fExpr.print(tab+1);
		getfStatement().print(tab+1);
	}

	public void generate(BufferedWriter writer, MemScope scope) throws IOException {
		MemScope myScope = new MemScope(scope);
		myScope.setLoop(true);

		boolean generate = true;
		if (fExpr instanceof Term) {
			Term t = (Term)fExpr;
			Type tmp = t.compute();
			if (tmp != null) {
				if (tmp.getfValue() == 0) {
					generate = false;
				}
			} else if(t instanceof Type) {
				Type type = (Type)t;
				if(type.getfValue() == 0) {
					generate = false;
				}
			}
		} 
		if (generate) {
			String lbl = myScope.getUniqueLabel();
			writer.write("while_" + lbl + ":\n");
			fExpr.setfRes(new IntType(true));
			fExpr.generate(writer, myScope);
			if(fExpr instanceof Type) {
				Type type = (Type)fExpr;
				writer.write("conv " + type.getPType() + " b\n");
			}
			writer.write("fjp end_while_" + lbl + "\n");
			
			fStatement.generate(writer, myScope);
			
			writer.write("ujp while_" + lbl + "\n" );
			writer.write("end_while_" + lbl + ":\n" );
		}
	}

	public Stmt getfStatement() {
		return fStatement;
	}

	public void setfStatement(Stmt fStatement) {
		this.fStatement = fStatement;
	}

}
